import re
import serial
import serial.tools.list_ports
import binascii
import time

def checkAvailableSerialPort():
    '''查看可用串口列表，得到串口的USB VID:PID'''
    com_list = list(serial.tools.list_ports.comports())
    if len(com_list) <= 0:
        print('No available COM port.')
    else:
        for com in com_list:
            print(list(com))

class serial_port:
    '''封装的serial_port类，采用vid:pid唯一确定串口'''
    def __init__(self,vid_pid,name,baudrate,write_mode='Normal'):
        self.vid_pid = vid_pid
        self.name = name
        self.baudrate = baudrate
        self.setWriteMode(write_mode)
        self.getSerialPort()

    def setWriteMode(self,write_mode):
        '''
            设置串口发送的模式
            - Normal:直接发送
            - Specific:更改DTR状态发送
        '''
        if write_mode in ['Normal','Specific']:
            self.write_mode = write_mode
        else:
            raise RuntimeError('No such write mode named {}.'.format(write_mode))

    def getSerialPort(self):
        '''
            根据vid_pid正则匹配，获取串口
            - 如果匹配，检查是否正常开启
            - 如果不匹配，抛出IOError
        '''
        com_list = list(serial.tools.list_ports.comports())
        if len(com_list) <= 0:
            raise IOError('No available COM port.')
        else:
            for com in com_list:
                if re.search(self.vid_pid, list(com)[2],re.I):
                    serial_name = list(com)[0]
                    serial_port = serial.Serial(port=serial_name,baudrate=self.baudrate)
                    serial_port.setDTR(True)
                    break
            if serial_port.is_open:
                print('Open the serial port for',self.name,'successfully.')
                self.port = serial_port
            else:
                raise IOError('Fail to the open serial port for ',self.name,'.')

    def serialWrite(self,message):
        '''
            按照串口发送模式封装后的发送方法
            - Normal:直接发送
            - Specific:更改DTR状态发送
        '''
        if self.write_mode == 'Normal':
            self.port.write(bytes.fromhex(message))
        elif self.write_mode == 'Specific':
            self.port.setDTR(True)
            self.port.write(bytes.fromhex(message))
            self.port.setDTR(False)

    def serialRead(self,buflen=-1):
        '''
            串口读取函数
            param:
            - buflen:为-1则将读取长度设置为当前缓冲区长度，否则采用输入的长度
            return：
            - data:包含b''的16进制字符串
        '''
        if buflen == -1:
            buflen = self.port.inWaiting()
        data = str(binascii.b2a_hex(self.port.read(buflen)))
        return data

if __name__ == '__main__':
    checkAvailableSerialPort()
    rplidar_serial = serial_port(vid_pid='10C4:EA60',name='rplidar',baudrate=115200,write_mode='Specific')
    rplidar_serial.serialWrite(message='A5 50')
    while True:
        data = rplidar_serial.serialRead()
        print(data)
        time.sleep(1)


